#ifndef socket_poll_h
#define socket_poll_h

#include <stdbool.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>

struct event {
    void *s;
    bool read;
    bool write;
};

static bool sp_invalid(int efd) {
    return -1 == efd;
}

static int sp_create() {
    return epoll_create(1024);
}

static void sp_release(int efd) {
    close(efd);
}

static int sp_add(int efd, int sock, void *ud) {
    struct epoll_event ev; // epoll_wait use
    ev.events = EPOLLIN;
    ev.data.ptr = ud;
    if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &ev)) {
        return 1;
    }
    return 0;
}

static void sp_del(int efd, int sock) {
    epoll_ctl(efd, EPOLL_CTL_DEL, sock, NULL);
}

static void sp_write(int efd, int sock, void *ud, bool enable) {
    struct epoll_event ev;
    ev.events = EPOLLIN | (enable ? EPOLLOUT : 0);
    ev.data.ptr = ud;
    epoll_ctl(efd, EPOLL_CTL_MOD, sock, &ev);
}

static int sp_wait(int efd, struct event *e, int max) {
    struct epoll_event ev[max];
    int n = epoll_wait(efd, ev, max, -1);
    for (int i = 0;i < n; ++i) {
        e[i].s = ev[i].data.ptr; // equal to sp_add ud
        uint32_t flag = ev[i].events;
        e[i].write = (flag & EPOLLOUT) != 0;
        e[i].read = (flag & EPOLLIN) != 0;
    }
    return n;
}

static void sp_nonblocking(int fd) {
    int flag = fcntl(fd, F_GETFL, 0);
    if (-1 == flag) {
        return;
    }
    fcntl(fd, F_SETFL, flag|O_NONBLOCK);
}

#endif